1 module mpdec.decimal;
2 
3 import mpdec.deimos;
4 import core.stdc.stdio:printf;
5 import std..string:toStringz,fromStringz;
6 import std.stdio;
7 import core.memory;
8 import core.stdc.stdlib;
9 
10 /* 
11 
12 MIT License
13 
14 Copyright (c) 2021 Pablo De Nápoli
15 
16 Permission is hereby granted, free of charge, to any person obtaining a copy
17 of this software and associated documentation files (the "Software"), to deal
18 in the Software without restriction, including without limitation the rights
19 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
20 copies of the Software, and to permit persons to whom the Software is
21 furnished to do so, subject to the following conditions:
22 
23 The above copyright notice and this permission notice shall be included in all
24 copies or substantial portions of the Software.
25 
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 SOFTWARE.
33 
34 */
35 
36 mpd_context_t decimal_ctx;
37 
38 void init_decimal(int prec) {
39   printf("Using libmpdec version %s \n",mpd_version);
40   mpd_init(&decimal_ctx,prec);
41 }
42 
43 void init_ieee_decimal(int bits) {
44     printf("Using libmpdec version %s \n",mpd_version);
45     mpd_ieee_context(&decimal_ctx, bits); 
46 }
47 
48 struct Decimal{
49     mpd_t* value;
50     private string name;
51 
52     //@disable this();
53 
54     this(mpd_t* v)
55     {
56       value=v;
57     }
58 
59     this(Decimal original)
60     {
61       //debug writeln("Call copy constructor");
62       value=mpd_qncopy(original.value);
63     }
64 
65     this(this)
66     {
67       //debug writeln("Calling this(this)");
68       if (value)
69         value = mpd_qncopy(value);
70     }
71 
72     this(string s)
73     {
74       value=mpd_new(&decimal_ctx);
75       immutable(char)* c_string = toStringz(s); 
76       GC.addRoot(cast(void*)c_string);
77       GC.setAttr(cast(void*)c_string, GC.BlkAttr.NO_MOVE);
78       mpd_set_string(value,c_string,&decimal_ctx);
79       GC.removeRoot(cast(void*)c_string);
80       GC.clrAttr(cast(void*)c_string, GC.BlkAttr.NO_MOVE);
81     }
82 
83     this(int x)
84     {
85       value=mpd_new(&decimal_ctx);
86       mpd_set_i32(value, x, &decimal_ctx);
87     }
88 
89     this(long x)
90     {
91       value=mpd_new(&decimal_ctx);
92       mpd_set_i64(value, x, &decimal_ctx);
93     }
94 
95     ~this()
96     {
97        //debug writeln("Calling mpd_del value=",value);
98        if (value)
99           mpd_del(value);
100        value=null;   
101     }
102 
103     // a string representation, used by write.
104     string toString() const  
105     {
106       if (value)
107       {
108         char* s= mpd_to_eng(value, 0); // 0 = exponential in lower case
109         auto s_string = cast(string) fromStringz(s); 
110         return s_string;
111       }
112       else return "null";
113     }
114 
115 
116     bool opEquals(Decimal rhs) const {
117       if (!value || !rhs.value) 
118             return false;
119        return mpd_cmp(value,rhs.value,&decimal_ctx)==0;
120     }
121 
122 
123     // unary operator overloading
124 
125     Decimal opUnary(string op)()
126     {
127      mpd_t* result;
128     if (!value) 
129             return this;
130     static if (op == "-") 
131     {
132         result=mpd_new(&decimal_ctx); 
133         mpd_minus(result,value,&decimal_ctx);
134         return Decimal(result);
135     }
136     else static if (op == "+") 
137     {
138         result=mpd_new(&decimal_ctx); 
139         mpd_plus(result,value,&decimal_ctx);
140         return Decimal(result);
141     }
142     else static if (op == "++") 
143     {
144         mpd_add_i32(value, value, 1,&decimal_ctx);
145         return this;
146     }
147     else static if (op == "--") 
148     {
149         mpd_sub_i32(value, value, 1,&decimal_ctx);
150         return this;
151     }
152     else static assert(0, "Operator "~op~" not implemented");
153     }
154 
155 
156 
157     // binary operator overloading
158 
159     Decimal opBinary(string op)(Decimal rhs)
160     {
161     if (!value || !rhs.value) 
162             return this;
163     mpd_t*  result= mpd_new(&decimal_ctx);
164     static if (op == "+") 
165     {
166         mpd_add(result,value,rhs.value,&decimal_ctx);
167     }
168     else static if (op == "-") 
169     {
170         mpd_sub(result,value,rhs.value,&decimal_ctx);
171     }
172     else static if (op == "*") 
173     {
174         mpd_mul(result,value,rhs.value,&decimal_ctx);
175     }
176     else static if (op == "/") 
177     {
178         mpd_div(result,value,rhs.value,&decimal_ctx);
179     }
180     else static if (op == "%") 
181     {
182         mpd_rem(result,value,rhs.value,&decimal_ctx);
183     }
184     else static if (op == "^^") 
185     {
186         mpd_pow(result,value,rhs.value,&decimal_ctx);
187     }
188     else static assert(0, "Operator "~op~" not implemented");
189     
190     return Decimal(result);
191     }
192 
193     // assign operator overloading
194 
195     Decimal opOpAssign(string op)(Decimal rhs)
196     {
197     if (!value || !rhs.value) 
198             return this;
199     static if (op == "+") 
200     {
201         mpd_add(value,value,rhs.value,&decimal_ctx);
202     }
203     else static if (op == "-") 
204     {
205         // debug write("value=");
206         mpd_print(value);
207         // debug write("rhs.value=");
208         mpd_print(rhs.value);
209         mpd_sub(value,value,rhs.value,&decimal_ctx);
210     }
211     else static if (op == "/") 
212     {
213         mpd_div(value,value,rhs.value,&decimal_ctx);
214     }
215     else static if (op == "%") 
216     {
217         mpd_rem(value,value,rhs.value,&decimal_ctx);
218     }
219     else static if (op == "^^") 
220     {
221         mpd_pow(value,value,rhs.value,&decimal_ctx);
222     }
223     else static assert(0, "opOpAssign: Operator "~op~" not implemented");   
224     return this;
225     }
226 
227         // comparison operator overloading
228 
229     const int opCmp(const Decimal rhs){
230         if (!value || !rhs.value) 
231             return false;
232         return  mpd_cmp(value,rhs.value,&decimal_ctx); 
233     }
234 
235     bool isfinite()
236     {
237       if (!value) return false;
238       return cast(bool) mpd_isfinite(value);
239     }
240 
241     bool isinfinite()
242     {
243       if (!value) return false;
244      return cast(bool) mpd_isinfinite(value);
245     }
246 
247     bool isnan()
248     {
249       if (!value) return false;
250      return cast(bool) mpd_isnan(value);
251     }
252 
253     bool isnegative()
254     {
255      if (!value) return false;
256      return cast(bool) mpd_isnegative(value);
257     }
258 
259     bool ispositive()
260     {
261      if (!value) return false;
262      return cast(bool) mpd_ispositive(value);
263     }
264 
265     bool isqnan()
266     {
267      if (!value) return false;
268      return cast(bool) mpd_isqnan(value);
269     }
270 
271     bool issigned()
272     {
273      if (!value) return false;
274      return cast(bool) mpd_issigned(value);
275     }
276 
277     bool issnan()
278     {
279      if (!value) return false;
280      return cast(bool) mpd_issnan(value);
281     }
282 
283     bool isspecial()
284     {
285      if (!value) return false;
286      return cast(bool) mpd_isspecial(value);
287     }
288 
289     bool iszero()
290     {
291      if (!value) return false;
292      return cast(bool) mpd_iszero(value);
293     }
294 
295     bool is_nonnegative()
296     {
297       return iszero() ||ispositive() ;   
298     }
299 
300     bool is_nonpositive()
301     {
302       return iszero()||isnegative();   
303     }
304 }
305  
306  Decimal decimal_abs(Decimal x)
307   {
308     mpd_t* result;
309     result=mpd_new(&decimal_ctx);
310     mpd_abs(result,x.value,&decimal_ctx);
311     return Decimal(result);        
312   }